package com.my.collection.stack.v14;

import com.google.common.base.Throwables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;

/**
 * Created by ZhongGang
 * at 2018/7/26 15:25
 */
public class BlockingStack<E> {
    private static final Logger LOGGER = LoggerFactory.getLogger(BlockingStack.class);

    private Object[] elements;
    private int count;
    private ReentrantLock lock = new ReentrantLock();

    public BlockingStack(int size) {
        this.elements = new Object[size];
    }

    public void put(E e) throws InterruptedException {
        try {
            lock.lock();
            LOGGER.info("try to put element {}", e);

            this.elements[this.count++] = e;
            LOGGER.info("put element {}", e);

            E take = take();
            LOGGER.info("take element {}", take);
        } finally {
            lock.unlock();
        }
    }

    public E take() throws InterruptedException {
        try {
            lock.lock();
            LOGGER.info("try to take element...");

            int position = --this.count;
            E e = (E) this.elements[position];
            this.elements[position] = null;
            return e;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws Exception {
        Random random = new Random();
        BlockingStack<Integer> blockingStack = new BlockingStack<>(5);
        blockingStack.put(random.nextInt(100));

//        for (int i = 0; i < 100; i++) {
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        blockingStack.put(random.nextInt(100));
//                    } catch (InterruptedException e) {
//                        LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(e));
//                    }
//                }
//            }).start();
//        }
    }
}
